#ifndef CVUTILS_H
#define CVUTILS_H
#include <QtCore>
#include <opencv2/opencv.hpp>
#include "json.hpp"
#include <algorithm>
#include <qobject.h>
#include <qprocess.h>
using json = nlohmann::json;

Q_DECLARE_METATYPE(cv::Mat)
struct ObjectInfo {
    std::vector<std::pair<int, int>> positionMap; // 物体中心坐标
    std::vector<float> rMap; // 物体最小外接圆半径
    int total = 0; // 物体总数
};
Q_DECLARE_METATYPE(ObjectInfo)
// 存储检测到的目标和角点
struct CardDetectionResult {
    cv::Rect boundingBox;                // 卡片边界框
    float confidence;                    // 检测置信度
    std::vector<cv::Point2f> corners;    // 角点坐标
};
Q_DECLARE_METATYPE(CardDetectionResult)
Q_DECLARE_METATYPE(std::vector<CardDetectionResult>)

namespace CvUtils
{
    //excel表结构分析器
    class tableStructure{
    public:
        json operator()(const json& textInfo){
            return exportToJson(textInfo["image_path"], textInfo);
        }
    private:
        struct CellData {
            int row;
            int col;
            int x;
            int y;
            int width;
            int height;
        };
        cv::Mat eraseRegions(cv::Mat& image, const json& data);
        json exportToJson(const std::string& imgPath, const json& textInfo);
    };


    enum markType {
        BasedOnEdge, // 基于轮廓
        BasedOnArea  // 基于区域
    };

    //物体计数(分水岭算法)
    class objectCounter : public QObject {
        Q_OBJECT
    public:
        objectCounter() {
            registerMetaType(); // 注册元类型
            initSlots();       // 初始化内部信号槽连接
        }
    private:
        markType m_markType = markType::BasedOnEdge;
        cv::Mat m_image;
    //这里通过信号槽来调用保证跨线程调用安全
    public slots:
        void slot_initImage(const cv::Mat& image);
        void slot_reCount();
        void slot_setMarkType(markType type);

    signals:
        void reCounted(ObjectInfo);
        void sig_initImage(const cv::Mat& image);
        void sig_reCount();
        void sig_setMarkType(markType type);

    private:
        void processWatershedResult(const cv::Mat& labels, ObjectInfo& result);
        void initSlots(){
            connect(this, &objectCounter::sig_initImage, this, &objectCounter::slot_initImage);
            connect(this, &objectCounter::sig_reCount, this, &objectCounter::slot_reCount);
            connect(this, &objectCounter::sig_setMarkType, this, &objectCounter::slot_setMarkType);
        }
        void registerMetaType(){
            qRegisterMetaType<ObjectInfo>("ObjectInfo");
            qRegisterMetaType<cv::Mat>("cv::Mat");
        }
    };

    //证件识别(yolov8-pose关键点检测)
    class cardCornerDetector : public QObject{
        Q_OBJECT
    public:
        cardCornerDetector();
        ~cardCornerDetector();
    public slots:
        // 实际处理槽函数(运行在工作线程)
        void slot_loadModel(const QString& modelPath);
        void slot_detect(const cv::Mat& frontImage, const cv::Mat& backImage);
        void slot_exitProcess();
        void initPythonProcess(); // 工作线程内初始化 Python 进程

    signals:
        // 外部调用接口信号
        void sig_loadModel(const QString& modelPath);
        void sig_detect(const cv::Mat& frontImage, const cv::Mat& backImage);
        void sig_exitProcess();

        // 结果反馈信号
        void sig_initFinished();
        void sig_modelLoaded(bool success, const QString& message);
        void sig_detectionFinished(const std::vector<CardDetectionResult>& fresults,
                                   const std::vector<CardDetectionResult>& bresults);
        void sig_errorOccurred(const QString& errorMsg);
        void sig_detectionVisualized(const cv::Mat& fvisualizedImage,
                                     const cv::Mat& bvisualizedImage);
        // 新增：退出完成信号（通知主线程可继续析构）
        void sig_exitFinished();
    private slots:
        void onPythonFinished(int exitCode, QProcess::ExitStatus exitStatus);

    private:
        // 初始化信号槽连接
        void initSlots();
        // 注册元类型
        void registerMetaTypes();
        // 绘制检测结果
        cv::Mat drawResults(const cv::Mat& image, const std::vector<CardDetectionResult>& results);

        // 保存 cv::Mat 为临时 PNG 文件，返回临时文件路径
        QString saveMatToTempFile(const cv::Mat& image, const QString& prefix);
        // 解析 JSON 结果为 CardDetectionResult 列表
        std::vector<CardDetectionResult> parseJsonResults(const json& jsonResults, const cv::Mat& sourceImage);

        // 发送模型加载命令到Python进程
        void sendLoadModelCommand();

    private:
        // Python 进程与临时文件管理
        QProcess* m_pythonProcess = nullptr;       // Python 进程实例
        QString m_pythonExePath;         // Python 解释器路径（需用户配置）
        QString m_inferScriptPath;       // YOLOv8 推理脚本路径（需用户配置）
        QString m_modelPath;             // .pt 模型路径
        bool m_modelLoaded = false;              // 模型是否加载（仅检查文件存在性）
        bool m_pythonProcessReady = false;   // Python进程是否就绪
        // 新增：标记是否已删除Python进程（避免双重释放）
        bool m_pythonProcessDeleted = false;

        // 新增：区分文件存在性和实际加载状态
        bool m_modelFileValid;       // 模型文件是否存在且有效
        // 临时文件路径（存储 front/back 图像）
        QString m_frontTempImgPath;
        QString m_backTempImgPath;

        // 保存当前检测的图像（用于后续绘制结果）
        cv::Mat m_currentFrontImage;
        cv::Mat m_currentBackImage;

        // 新增：命令类型枚举，用于区分Python进程处理的命令
        enum class CommandType {
            LoadModel,
            Detect
        };
        CommandType m_currentCommand;
    };

};

#endif // CVUTILS_H
